﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using System.Web.UI.WebControls;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using PagedList;
using RechercheEmplois.DAL;
using RechercheEmplois.Models;
using RechercheEmplois.ViewModel;
using RTE;
using WebGrease.Css.Extensions;
using RechercheEmplois.Utilities;

namespace RechercheEmplois
{
    public class OffreController : Controller
    {
        private ApplicationDbContext db = new ApplicationDbContext();
        private UserManager<ApplicationUser> UserManager;
        // GET: /Offre/
        public OffreController()
        {
            UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
        }
        public ActionResult Index(string DomaineSelectedID, string ProvineSelectedID, string OffreTypeSelectedID, string searchKeys, string triValeur, string triOrdre, string currentFilter, int? page, string[] selectedProvines, string[] selectedTypes, string[] selectedSecteurs, int? remuValue, string[] selectedNiveauEtudes)
        {
            int domaineSelectedId, provineSelectedId;
            OffreType offreTypeSelectedId;
            //Sauvegarder les criteres recherchees
            #region Stocker les parametres à parcourir
            ViewBag.DomaineSelectedID = DomaineSelectedID;
            ViewBag.ProvineSelectedID = ProvineSelectedID;
            ViewBag.OffreTypeSelectedID = OffreTypeSelectedID;
            ViewBag.CurrentSort = triValeur;
            ViewBag.CurrentSortOrder = triOrdre;
            if (searchKeys != null)
            {
                page = 1;
            }
            else
            {
                searchKeys = currentFilter;
            }
            ViewBag.CurrentSearch = searchKeys;
            if (page == null || page == 1)
            {
                Session["SelectedTypes"] = selectedTypes;
                Session["SelectedNiveauEtudes"] = selectedNiveauEtudes;
                if (selectedProvines != null)
                {
                    var provines = new List<Provine>();
                    selectedProvines.ForEach(p => provines.Add(db.Provines.Single(pro => pro.ID.ToString().Equals(p))));
                    //ViewBag.SelectedProvines = provines;
                    Session["SelectedProvines"] = provines;
                }
                if (selectedSecteurs != null)
                {
                    var secteurs = new List<Domaine>();
                    selectedSecteurs.ForEach(p => secteurs.Add(db.Domaines.Single(dom => dom.ID.ToString().Equals(p))));
                    //ViewBag.SelectedSecteurs = secteurs;
                    Session["SelectedSecteurs"] = secteurs;
                }
            }
            ViewBag.Remuneration = remuValue; 
            #endregion

            var viewModel = new OffresRecherchesVM();
            viewModel.Offres = db.Offres.Include(o => o.Domaine).Include(o => o.Recruiteur).Include(o => o.Ville).Include(o=> o.MotCles).Where(e => e.Valide > 0);

            //Rechercher rapidement
            #region Rechercher par domaine, provine, offretype
            if (!string.IsNullOrEmpty(DomaineSelectedID))
            {
                domaineSelectedId = int.Parse(DomaineSelectedID);
                viewModel.Offres = viewModel.Offres.Where(o => o.DomaineID == domaineSelectedId);
            }
            if (!string.IsNullOrEmpty(ProvineSelectedID))
            {
                provineSelectedId = int.Parse(ProvineSelectedID);
                viewModel.Offres = viewModel.Offres.Where(o => o.Ville.ProvineID == provineSelectedId);
            }
            if (OffreType.TryParse(OffreTypeSelectedID, out offreTypeSelectedId))
            {
                viewModel.Offres = viewModel.Offres.Where(o => o.Type == offreTypeSelectedId);
            } 
            #endregion

            //Sort liste des offres (Rechercher avancees)
            var array = viewModel.Offres.OrderByDescending(e => e.DateCreated).ToArray();
            Array.Sort(array, new OffreComparator(searchKeys, selectedProvines, selectedTypes, selectedSecteurs, selectedNiveauEtudes, remuValue));
            //Exclude les offres qui ne remplit pas les conditions
            array.ForEach(a => Debug.WriteLine(a));
            viewModel.Offres = array.Where(o => o.Probability > 0.0f);   

            #region Rechercher par mot clefs
            //if (!string.IsNullOrEmpty(searchKeys))
            //{
            //    string[] keys = searchKeys.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            //    //Rechercher par les titres
            //    var motClesCorrect = new Dictionary<Int32, Int32>();
            //    viewModel.Offres.ForEach(o =>
            //    {
            //        int count = 0;
            //        o.MotCles.ForEach(m =>
            //        {
            //            keys.ForEach(k =>
            //            {
            //                if (m.Libelle.ToLower().Contains(k.ToLower()))
            //                {
            //                    count++;
            //                }
            //            });
            //        });
            //        motClesCorrect.Add(o.ID, count);
            //    });
            //    var ordedList = motClesCorrect.OrderByDescending(o => o.Value);
            //    var offresTrouvees = new List<Offre>();
            //    //Trier default par nombre de mot cles correcpondant
            //    foreach (var valuePair in ordedList)
            //    {
            //        if (valuePair.Value == 0)
            //            break;
            //        offresTrouvees.Add(viewModel.Offres.Single(o => o.ID == valuePair.Key));
            //    }
            //    viewModel.Offres = offresTrouvees;
            //} 
            #endregion

            #region Trier par les autres parametres
            if (!string.IsNullOrEmpty(triValeur))
            {
                switch (triValeur)
                {
                    case "domaine":
                        viewModel.Offres = triOrdre == "asc" ? viewModel.Offres.OrderBy(o => o.Domaine.Libelle) : viewModel.Offres.OrderByDescending(o => o.Domaine.Libelle);
                        break;
                    case "titre":
                        viewModel.Offres = triOrdre == "asc" ? viewModel.Offres.OrderBy(o => o.Libelle) : viewModel.Offres.OrderByDescending(o => o.Libelle);
                        break;
                    case "type":
                        viewModel.Offres = triOrdre == "asc" ? viewModel.Offres.OrderBy(o => o.Type) : viewModel.Offres.OrderByDescending(o => o.Type);
                        break;
                    case "ville":
                        viewModel.Offres = triOrdre == "asc" ? viewModel.Offres.OrderBy(o => o.Ville.Libelle) : viewModel.Offres.OrderByDescending(o => o.Ville.Libelle);
                        break;
                    case "provine":
                        viewModel.Offres = triOrdre == "asc" ? viewModel.Offres.OrderBy(o => o.Ville.Provine.Libelle) : viewModel.Offres.OrderByDescending(o => o.Ville.Provine.Libelle);
                        break;
                }
            }
            
            #endregion

            #region Paging
            int pageSize = 3;
            int pageNumber = (page ?? 1);
            var linqListOffre = from offre in viewModel.Offres
                                select offre;
            viewModel.OffresPaged = linqListOffre.ToPagedList(pageNumber, pageSize); 
            #endregion

            #region Recuperer les offre sauvegardees
            try
            {
                //User not login
                var user = UserManager.FindById(User.Identity.GetUserId());
                viewModel.OffreSauvegardes = user.Utilisateur.Sauvegardes;
                viewModel.OffreSauvegardes.ForEach(s =>
                {
                    int l = s.Offre.Description.Length;
                    s.Offre.Description = s.Offre.Description.Substring(0, l > 50 ? 50 : l) + "...";
                });
            }
            catch (Exception)
            {
                viewModel.OffreSauvegardes = new List<Sauvegarde>();
            } 
            #endregion

            #region Rechercher Rapidement Dialog
            var listProvines = new List<SelectListItem>();
            db.Provines.ForEach(p =>
            {
                listProvines.Add(new SelectListItem() { Selected = false, Text = p.Libelle, Value = p.ID.ToString() });
            });
            viewModel.Provines = listProvines;
            var listDomaines = new List<SelectListItem>();
            db.Domaines.ForEach(p =>
            {
                listDomaines.Add(new SelectListItem() { Selected = false, Text = p.Libelle, Value = p.ID.ToString() });
            });
            viewModel.Domaines = listDomaines;
            var listTypes = new List<SelectListItem>();
            Enum.GetValues(typeof(OffreType)).Cast<OffreType>().ForEach(p => listTypes.Add(new SelectListItem() { Selected = false, Text = p.ToString(), Value = p.ToString() }));
            viewModel.OffreTypes = listTypes; 
            #endregion

            return View(viewModel);
        }

        // GET: /Offre/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Offre offre = db.Offres.Find(id);
            if (offre == null)
            {
                return HttpNotFound();
            }
            if (User.Identity.IsAuthenticated)
            {
                var user = UserManager.FindById(User.Identity.GetUserId()).Utilisateur;
                var userType = user.GroupUtilisateur.Libelle;
                ViewBag.UserType = userType;
                if (userType == "Recruiteur")
                {
                    ViewBag.IsRecruiteur = offre.UtilisateurID == user.ID;
                }
            }

            return View(offre);
        }

        // GET: /Offre/Create
        public ActionResult Create()
        {
            var listeVilles = new List<SelectListItem>();
            db.Villes.ForEach(p =>
            {
                listeVilles.Add(new SelectListItem() { Selected = false, Text = p.Libelle, Value = p.ID.ToString() });
            });
            var listeDomaines = new List<SelectListItem>();
            db.Domaines.ForEach(p =>
            {
                listeDomaines.Add(new SelectListItem() { Selected = false, Text = p.Libelle, Value = p.ID.ToString() });
            });
            var listTypes = new List<SelectListItem>();
            Enum.GetValues(typeof(OffreType)).Cast<OffreType>().ForEach(p => listTypes.Add(new SelectListItem() { Selected = false, Text = p.ToString(), Value = p.ToString() }));

            ViewBag.listeDomaines = listeDomaines;
            ViewBag.listeVilles = listeVilles;
            ViewBag.Types = listTypes;

            return View();
        }

        // POST: /Offre/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        public ActionResult Create([Bind(Include = "ID,Libelle,NiveauEtude,Description,HoraireTravail,RenumHoraire,DebutContrat,FinContrat,ExpMin,Commentaire,Type,DomaineID,VilleID,TagWords")] Offre offre)
        {
            if (ModelState.IsValid)
            {
                var user = UserManager.FindById(User.Identity.GetUserId());
                offre.UtilisateurID = user.Utilisateur.ID;
                offre.DateCreated = DateTime.Now;
                //Mot cles
                string[] motcles = offre.TagWords.Split(new string[]{","}, StringSplitOptions.RemoveEmptyEntries);
                offre.MotCles = new List<MotCle>();
                foreach (string m in motcles)
                {
                    bool trouve = false;
                    db.MotCles.ForEach(mt =>
                    {
                        if (mt.Libelle.Equals(m, StringComparison.OrdinalIgnoreCase))
                        {
                            trouve = true;
                        }
                    });
                    if (!trouve)
                    {
                        MotCle motCle = new MotCle() {Libelle = m.ToLower()};
                        db.MotCles.Add(motCle);
                        db.SaveChanges();
                    }
                    MotCle mot = db.MotCles.Single(s => s.Libelle == m);
                    offre.MotCles.Add(mot);
                };
                db.Offres.Add(offre);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            var listeVilles = new List<SelectListItem>();
            db.Villes.ForEach(p =>
            {
                listeVilles.Add(new SelectListItem() { Selected = false, Text = p.Libelle, Value = p.ID.ToString() });
            });
            var listeDomaines = new List<SelectListItem>();
            db.Domaines.ForEach(p =>
            {
                listeDomaines.Add(new SelectListItem() { Selected = false, Text = p.Libelle, Value = p.ID.ToString() });
            });
            var listTypes = new List<SelectListItem>();
            Enum.GetValues(typeof(OffreType)).Cast<OffreType>().ForEach(p => listTypes.Add(new SelectListItem() { Selected = false, Text = p.ToString(), Value = p.ToString() }));

            ViewBag.listeDomaines = listeDomaines;
            ViewBag.listeVilles = listeVilles;
            ViewBag.Types = listTypes;

            return View(offre);
        }

        // GET: /Offre/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Offre offre = db.Offres.Find(id);
            if (offre == null)
            {
                return HttpNotFound();
            }

            var tagwords = from tag in offre.MotCles
                select tag.Libelle;
            offre.TagWords = string.Join(",", tagwords);
            
            var listeVilles = new List<SelectListItem>();
            db.Villes.ForEach(p =>
            {
                listeVilles.Add(new SelectListItem() { Selected = false, Text = p.Libelle, Value = p.ID.ToString() });
            });
            var listeDomaines = new List<SelectListItem>();
            db.Domaines.ForEach(p =>
            {
                listeDomaines.Add(new SelectListItem() { Selected = false, Text = p.Libelle, Value = p.ID.ToString() });
            });
            var listTypes = new List<SelectListItem>();
            Enum.GetValues(typeof(OffreType)).Cast<OffreType>().ForEach(p => listTypes.Add(new SelectListItem() { Selected = false, Text = p.ToString(), Value = p.ToString() }));

            ViewBag.listeDomaines = listeDomaines;
            ViewBag.listeVilles = listeVilles;
            ViewBag.Types = listTypes;
            Session["MotCles"] = offre.MotCles;
            return View(offre);
        }

        // POST: /Offre/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        public ActionResult Edit(int? id, string[] virtuel)
        {
            //[Bind(Include="ID,Libelle,NiveauEtude,Description,HoraireTravail,RenumHoraire,DebutContrat,FinContrat,ExpMin,Commentaire,Type,DomaineID,VilleID,TagWords")] Offre offre
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var offre = db.Offres.Include(i => i.MotCles).Where(i => i.ID == id).Single();

            if (TryUpdateModel(offre, "",
                    new string[] { "Libelle", "NiveauEtude", "Description", "HoraireTravail", "RenumHoraire", "DebutContrat", "FinContrat", "ExpMin", "Commentaire", "Type", "DomaineID", "VilleID", "TagWords" }))
            {
                //Mot cles
                string[] motcles = offre.TagWords.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                var listeSuppimera = new List<MotCle>();
                foreach (MotCle mt in offre.MotCles)
                {
                    bool trouve = false;
                    foreach (string mot in motcles)
                    {
                        if (mt.Libelle.Equals(mot, StringComparison.OrdinalIgnoreCase))
                        {
                            trouve = true;
                            break;
                        }
                    };
                    if (!trouve)
                    {
                        listeSuppimera.Add(mt);
                    }
                };
                listeSuppimera.ForEach(m => offre.MotCles.Remove(m));
                foreach (string m in motcles)
                {
                    bool trouve = false;
                    offre.MotCles.ForEach(mt =>
                    {
                        if (mt.Libelle.Equals(m, StringComparison.OrdinalIgnoreCase))
                        {
                            trouve = true;
                        }
                    });
                    if (trouve)
                    {
                        continue;
                    }
                    db.MotCles.ForEach(mt =>
                    {
                        if (mt.Libelle.Equals(m, StringComparison.OrdinalIgnoreCase))
                        {
                            trouve = true;
                        }
                    });
                    if (!trouve)
                    {
                        MotCle motCle = new MotCle() { Libelle = m.ToLower() };
                        db.MotCles.Add(motCle);
                        db.SaveChanges();
                    }
                    MotCle mot = db.MotCles.Single(s => s.Libelle == m);
                    offre.MotCles.Add(mot);
                };
 
                db.Entry(offre).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            var listeVilles = new List<SelectListItem>();
            db.Villes.ForEach(p =>
            {
                listeVilles.Add(new SelectListItem() { Selected = false, Text = p.Libelle, Value = p.ID.ToString() });
            });
            var listeDomaines = new List<SelectListItem>();
            db.Domaines.ForEach(p =>
            {
                listeDomaines.Add(new SelectListItem() { Selected = false, Text = p.Libelle, Value = p.ID.ToString() });
            });
            var listTypes = new List<SelectListItem>();
            Enum.GetValues(typeof(OffreType)).Cast<OffreType>().ForEach(p => listTypes.Add(new SelectListItem() { Selected = false, Text = p.ToString(), Value = p.ToString() }));

            ViewBag.listeDomaines = listeDomaines;
            ViewBag.listeVilles = listeVilles;
            ViewBag.Types = listTypes;
            return View(offre);
        }

        // GET: /Offre/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Offre offre = db.Offres.Find(id);
            if (offre == null)
            {
                return HttpNotFound();
            }
            return View(offre);
        }

        // POST: /Offre/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            Offre offre = db.Offres.Find(id);
            db.Offres.Remove(offre);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        [Authorize(Roles = "Administrator")]
        public ActionResult Valider(int id)
        {
            var offre = db.Offres.Find(id);
            offre.Valide = offre.Valide == 0 ? 1 : 0;
            db.Entry(offre).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Manage", "Account");
        }

        public PartialViewResult GetMessage(string title, string body)
        {
            var model = new DialogSimpleVM() {Body = body, Title = title};
            return PartialView("_DialogSimple", model);
        }

        public ActionResult RechercherAvancee()
        {
            var model = new OffresRecherchesAvancesVM();
            model.ListeProvines = db.Provines.ToList();
            model.ListeOffreTypes = Enum.GetValues(typeof(OffreType)).Cast<OffreType>().ToList();
            model.ListeDomaines = db.Domaines.ToList();
            var listeNiveauEtude = new List<string>(){
                "Enseignement secondaire general",
                "Bac professionnel", 
                "Enseignement secondaire technique", 
                "CAP / BEP", 
                "Enseignement secondaire artistique", 
                "BTS / DUT / IUT", 
                "Specialisation", 
                "Classes préparatoires", 
                "Enseignement secondaire professionnel", 
                "Universités", 
                "Pas d'importance", 
                "Ecoles de commerce", 
                "Autres", 
                "Ecoles d'ingénieurs", 
                "Bac Général / Bac Technologique"
            };
            model.ListesNiveauEtudes = listeNiveauEtude;

            return View(model);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}
